﻿#include	"Engine.String.hpp"

#include	<algorithm>
#include	<cstring>
#include	<mutex>

namespace Engine { namespace String {

	void Copy(char * szDst, const char * szSrc, size_t nSizeOfDst) {
		::memset(szDst, 0, nSizeOfDst);
		size_t nSrcLen = ::strlen(szSrc);
	#if defined(_WIN32) && defined(_MSC_VER)
		::strncpy_s(szDst, nSizeOfDst, szSrc, nSrcLen);
	#else
		::strncpy(szDst, szSrc, std::min(nSizeOfDst, nSrcLen));
	#endif
	}

	std::string Trim(const std::string & szTarget) {
		if (szTarget.empty()) return szTarget;
		size_t nStart	= szTarget.find_first_not_of(" \t\r\n");
		size_t nEnd		= szTarget.find_last_not_of(" \t\r\n");
		if (nStart == std::string::npos) return std::string("");
		return szTarget.substr(nStart, nEnd - nStart + 1);
	}

	std::string Format(const char * pStrFmt, ...) {
		va_list args;
		va_start(args, pStrFmt);
		std::string szRet = FormatV(pStrFmt, args);
		va_end(args);
		return std::move(szRet);
	}

	std::string FormatV(const char * pStrFmt, va_list args) {
		static std::mutex iLock;
		static char pBuffer[8 * 1024];

		std::unique_lock<std::mutex> iAuto(iLock);
		memset(pBuffer, 0, 8 * 1024);
	#if defined(_WIN32) && defined(_MSC_VER)
		vsnprintf_s(pBuffer, 8 * 1024, pStrFmt, args);
	#else
		vsnprintf(pBuffer, 8 * 1024, pStrFmt, args);
	#endif
		return std::string(pBuffer);
	}

	std::string ToUpper(const std::string & szTarget) {
		std::string szResult(szTarget);
		for (size_t nIdx = 0; nIdx < szResult.length(); ++nIdx) {
			if (szResult[nIdx] >= 'a' && szResult[nIdx] <= 'z')
				szResult[nIdx] = szResult[nIdx] + 'A' - 'a';
		}
		return std::move(szResult);
	}

	std::string ToLower(const std::string & szTarget) {
		std::string szResult(szTarget);
		for (size_t nIdx = 0; nIdx < szResult.length(); ++nIdx) {
			if (szResult[nIdx] >= 'A' && szResult[nIdx] <= 'Z')
				szResult[nIdx] = szResult[nIdx] + 'a' - 'A';
		}
		return std::move(szResult);
	}

	std::vector<std::string> Split(const std::string & szTarget, const std::string & szSpec) {
		std::vector<std::string> vResult;
		if (!szTarget.empty()) {
			size_t nStart = szTarget.find_first_of(szSpec), nEnd = 0;
			while (nStart != std::string::npos) {
				nEnd = szTarget.find_first_of(szSpec, nStart);
				vResult.push_back(szTarget.substr(nStart, nEnd - nStart));
				if (nEnd == std::string::npos) break;
				nStart = szTarget.find_first_not_of(szSpec, nEnd + 1);
			}
		}
		return std::move(vResult);
	}

}}

